// Copyright 2013 The Go Circuit Project
// Use of this source code is governed by the license for
// The Go Circuit Project, found in the LICENSE file.
//
// Authors:
//   2013 Petar Maymounkov <p@gocircuit.org>

package shutter

import (
	"bytes"
	"fmt"
	"reflect"
	"runtime"
	"runtime/pprof"
	"strconv"

	"circuit/kit/rh"
	"circuit/kit/rh/ns"
)

type dbg struct{}

func NewDbg() rh.FID {
	return ns.NewFID("dbg", dbg{})
}

func (dbg) Numcpu() rh.FID {
	return ns.NewStringFID(func() string {
		return strconv.Itoa(runtime.NumCPU())
	})
}

func (dbg) Numgoroutine() rh.FID {
	return ns.NewStringFID(func() string {
		return strconv.Itoa(runtime.NumGoroutine())
	})
}

func (dbg) Mem() rh.FID {
	return ns.NewStringFID(func() string {
		var m runtime.MemStats
		runtime.ReadMemStats(&m)
		return printStruct(m)
	})
}

func (dbg) Goroutine() rh.FID {
	return ns.NewStringFID(func() string {
		var w bytes.Buffer
		pprof.Lookup("goroutine").WriteTo(&w, 1)
		return w.String()
	})
}

func (dbg) Block() rh.FID {
	return ns.NewStringFID(func() string {
		var w bytes.Buffer
		pprof.Lookup("block").WriteTo(&w, 1)
		return w.String()
	})
}

func printStruct(i interface{}) string {
	var v = reflect.ValueOf(i)
	var t = reflect.TypeOf(i)
	var w bytes.Buffer
	for j := 0; j < t.NumField(); j++ {
		var f = t.Field(j)
		switch f.Type.Kind() {
		case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
			reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr,
			reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
			//
			fmt.Fprintf(&w, "%s: %v\n", f.Name, v.Field(j).Interface())
		default: //Array, Chan, Func, Interface, Map, Ptr, Slice, String, Struct, UnsafePointer
			fmt.Fprintf(&w, "%s: (skipping)\n", f.Name)
		}
	}
	return w.String()
}
